package org.sgx.gapigui.client.ui.actions.drive;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.sgx.gapigui.client.ui.editableModels.drive.DriveFile;
import org.sgx.gwteditors.client.editor.Editor;
import org.sgx.gwteditors.client.impl1.complex.PropertyHaverEditor2;
import org.vectomatic.dnd.DataTransferExt;
import org.vectomatic.dnd.DropPanel;
import org.vectomatic.file.Blob;
import org.vectomatic.file.ErrorCode;
import org.vectomatic.file.File;
import org.vectomatic.file.FileError;
import org.vectomatic.file.FileList;
import org.vectomatic.file.FileReader;
import org.vectomatic.file.events.ErrorEvent;
import org.vectomatic.file.events.ErrorHandler;
import org.vectomatic.file.events.LoadEndEvent;
import org.vectomatic.file.events.LoadEndHandler;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DragEnterEvent;
import com.google.gwt.event.dom.client.DragEnterHandler;
import com.google.gwt.event.dom.client.DragLeaveEvent;
import com.google.gwt.event.dom.client.DragLeaveHandler;
import com.google.gwt.event.dom.client.DragOverEvent;
import com.google.gwt.event.dom.client.DragOverHandler;
import com.google.gwt.event.dom.client.DropEvent;
import com.google.gwt.event.dom.client.DropHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class DriveFiles1 extends Composite {

	private static DriveFiles1UiBinder uiBinder = GWT.create(DriveFiles1UiBinder.class);

	interface DriveFiles1UiBinder extends UiBinder<Widget, DriveFiles1> {
	}

//	List<Editor<DriveFile>> driveFiles;
	private FileReader reader;
	private List<File> readQueue;
//	private List<DriveFile> readQueue;
	Map<File, Editor<DriveFile>> editors;

	@UiField VerticalPanel dropFilesContainer; 
	FlowPanel fileListPanel; 
	
	public DriveFiles1() {
		initWidget(uiBinder.createAndBindUi(this));
		editors=new HashMap<File, Editor<DriveFile>>(); 
//		driveFiles = new LinkedList<Editor<DriveFile>>();
		initReader();
		initDropFiles(); 
	}
	private void initReader() {
		reader = new FileReader();
		reader.addLoadEndHandler(new LoadEndHandler() {
			/**
			 * This handler is invoked when FileReader.readAsText(),
			 * FileReader.readAsBinaryString() or FileReader.readAsArrayBuffer()
			 * successfully completes
			 */
			@Override
			public void onLoadEnd(LoadEndEvent event) {
//				System.out.println("reader onLoadEnd");
				if (reader.getError() == null) {
					if (readQueue.size() > 0) {
						File file = readQueue.get(0);
						String content = reader.getStringResult(); 
						Editor<DriveFile> fileEditor = editors.get(file); 
						DriveFile fileDrive = fileEditor.flush(); 
						System.out.println("setting content: "+(content==null));
						fileDrive.setContent(content); 
						try {
//							imagePanel.add(createThumbnail(file));
//							FileUtils.
//							System.out.println("file readed: "+file.getName()+" - content length: "+content.length()+" - "+content);
						} finally {
							readQueue.remove(0);
							readNextFile();
						}
					}
					else {
						afterReadAllFiles(); 
					}
				}
			}
		});		
		reader.addErrorHandler(new ErrorHandler() {
			/**
			 * This handler is invoked when FileReader.readAsText(),
			 * FileReader.readAsBinaryString() or FileReader.readAsArrayBuffer()
			 * fails
			 */
			@Override
			public void onError(ErrorEvent event) {
				if (readQueue.size() > 0) {
					File file = readQueue.get(0);
					handleError(file);
					readQueue.remove(0);
					readNextFile();
				}
			}
		});

		readQueue = new LinkedList<File>();
	}
	void handleError(File file) {
		FileError error = reader.getError();
		String errorDesc = "";
		if (error != null) {
			ErrorCode errorCode = error.getCode();
			if (errorCode != null) {
				errorDesc = ": " + errorCode.name();
			}
		}
		Window.alert("File loading error for file: " + file.getName() + "\n" + errorDesc);
	}
	private void readNextFile() {
		boolean useTypedArrays = true;
		if (readQueue.size() > 0) {
			File file = readQueue.get(0);
			
			reader.readAsText(file);
			
			String type = file.getType();
			try {

//				System.out.println("readNextFile type: "+type);
				
				reader.readAsText(file);
				
//				if ("image/svg+xml".equals(type)) {
//					reader.readAsText(file);	
//				} else if (type.startsWith("image/png")) {
//					// Do not use the FileReader for PNG.
//					// Take advantage of the fact the browser can
//					// provide a directly usable blob:// URL
////					imagePanel.add(createThumbnail(file));
//					readQueue.remove(0);
//					readNextFile();
//				} else if (type.startsWith("image/")) {
//					// For other image types (GIF, JPEG), load them
//					// as typed arrays
//					if (useTypedArrays) {
//						reader.readAsArrayBuffer(file);
//					} else {
//						reader.readAsBinaryString(file);
//					}
//				} else if (type.startsWith("text/")) {
////					// If the file is larger than 1kb, read only the first 1000 characters
////					// to demonstrate file slicing
//					Blob blob = file;
////					if (file.getSize() > 0) {
////						blob = file.slice(0, 1000, "text/plain; charset=utf-8");
////					}
//					reader.readAsText(blob);
//				}
			} catch(Throwable t) {
				// Necessary for FF (see bug https://bugzilla.mozilla.org/show_bug.cgi?id=701154)
				// Standard-complying browsers will not go in this branch
				handleError(file);
				readQueue.remove(0);
				readNextFile();
			}
		}
	}
	
	protected void proccessDropFiles(DropEvent event) {
		DataTransferExt dte = event.getDataTransfer().<DataTransferExt>cast();
		FileList files = dte.getFiles(); 
		for (int i = 0; i < files.getLength(); i++) {
			File file = files.getItem(i);
			readQueue.add(file); 
//			System.out.println("FILE dropped detected : title: "+file.getName()+", size: "+file.getSize()+", type: "+file.getType());
			addFileToList(file);			
		}
	}
	private void addFileToList(File file) {
//		Array1DEditor2<DriveFile> listEditor = new Array1DEditor2<DriveFile>();
		DriveFile df = DriveFile.from(file); 
		PropertyHaverEditor2<DriveFile> ed = new PropertyHaverEditor2<DriveFile>(); 
		fileListPanel.add(ed); 
		ed.load(df);
		editors.put(file, ed); 
//		driveFiles.add(ed); 
	}
	private void initDropFiles() {
		
		DropPanel dp = new DropPanel(); 
		
		dp.add(new Label("drop your files here")); 
		
		dropFilesContainer.add(dp);		
		
		dp.addDragEnterHandler(new DragEnterHandler() {			
			@Override
			public void onDragEnter(DragEnterEvent event) {
				event.stopPropagation(); 
				event.preventDefault(); 
			}
		}); 
		
		dp.addDragLeaveHandler(new DragLeaveHandler() {			
			@Override
			public void onDragLeave(DragLeaveEvent event) {
				event.stopPropagation(); 
				event.preventDefault(); 
			}
		}); 
		
		dp.addDragOverHandler(new DragOverHandler() {			
			@Override
			public void onDragOver(DragOverEvent event) {

				event.stopPropagation(); 
				event.preventDefault(); 
			}
		}); 
		
		dp.addDropHandler(new DropHandler() {			
			@Override
			public void onDrop(DropEvent event) {
				proccessDropFiles(event); 
				event.stopPropagation(); 
				event.preventDefault(); 
			}
		}); 
		
		fileListPanel = new FlowPanel(); 
		dropFilesContainer.add(fileListPanel); 
		
		Button saveButton = new Button("Save files in Drive");  
		dropFilesContainer.add(saveButton); 
		saveButton.addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) {
				doSaveFilesInDrive();
			}
		}); 
	}
	protected void doSaveFilesInDrive() {
		readNextFile();
//		afterReadAllFiles();
//		for(Editor<DriveFile> ed : driveFiles) {
//			DriveFile df = ed.flush(); 
//		}
	}
	private void afterReadAllFiles() {
//		Controller.
		//at this point all files has its content attribute loaded
		for(File file : editors.keySet()) {
			DriveFile driveFile = editors.get(file).flush();
			
//			System.out.println("setting content: "+content==null);
			String content = driveFile.getContent();
			System.out.println("savefile: "+driveFile.getTitle()+" - "+(content==null));//driveFile.getContent());//.length());
		}
	}
		
	
}
